﻿using Application.Utils;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Neoit.Utils.Extensions;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace Web.Middlewares
{
    /* 1.使用actionFilter记录操作日志
     * 2.默认记录：post、put、delete操作；无get
     * 3.自定义指定：
     *      如某post方法上标记为不记录日志[OperationLogTag(false)]、
     *      某get方法上标记为需记录日志[OperationLogTag(true)]；
     *      重写标题 [OperationLogTag(title:"新增用户")
     */
    public class OperationLogFilter : IActionFilter
    {
        private readonly IMenuService _menuService;
        private readonly JobManagerDbContext _dbContext;
        private readonly IServiceScopeFactory _serviceScopeFactory;
        private readonly Accessor _accessor;
        public OperationLogFilter(IMenuService menuService, Accessor accessor, JobManagerDbContext dbContext, IServiceScopeFactory serviceScopeFactory)
        {
            _menuService = menuService;
            _accessor = accessor;
            _dbContext = dbContext;
            _serviceScopeFactory = serviceScopeFactory;
        }
        public void OnActionExecuted(ActionExecutedContext context) { }

        public async void OnActionExecuting(ActionExecutingContext context)
        {
            if (_accessor.ManagerId == 0) return;
            var controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
            var isTag = controllerActionDescriptor.MethodInfo.IsDefined(typeof(OperationLogTag), true);
            var method = context.HttpContext.Request.Method;
            var apiPath = context.HttpContext.Request.Path.ToString().ToLower();
            apiPath = apiPath.Substring(1, apiPath.Length - 1);
            if (apiPath.StartsWith("api/")) apiPath = apiPath.Substring(4, apiPath.Length - 4);
            var title = string.Empty;
            //var recordRequestBodyAll = false;
            //var isRecordBody = true;
            RecordBody recordBody = RecordBody.part;
            if (isTag)//已标记
            {
                var param = controllerActionDescriptor.MethodInfo.CustomAttributes.Where(s => s.AttributeType == typeof(OperationLogTag)).FirstOrDefault().ConstructorArguments;
                var isWrite = Convert.ToBoolean(param[0].Value);
                if (!isWrite) return;//标记为不记录时
                title = Convert.ToString(param[1].Value);
                recordBody = (RecordBody)(param[2].Value);
                if (title == null)
                {
                    var listMenu = _menuService.GetAllMenu();
                    title = listMenu.FirstOrDefault(s => s.RoutePath == apiPath)?.Title;
                }
            }
            else//未标记
            {
                if (method == "GET") return;//无标记时，get不记录
                var listMenu = _menuService.GetAllMenu();
                title = listMenu.FirstOrDefault(s => s.RoutePath == apiPath)?.Title;
            }
            var options = new JsonSerializerOptions
            {
                DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
            };

            var requestBody = context.ActionArguments.ToJson();
            requestBody = recordBody switch
            {
                RecordBody.none => null,
                RecordBody.part => requestBody.Omit(256),
                RecordBody.all => requestBody,
                _ => null
            };
            var operationLog = new SysLogOperation
            {
                Ip = context.HttpContext.RealIP(),
                Title = title,
                Api = apiPath,
                OperatorId = _accessor.ManagerId,
                OperatorName = _accessor.ManagerName,
                Note = requestBody.Omit(497)
            };
            //日志case：1.修改数据的id 2.修改了哪些信息(增，删，改，查) 3.结果
            // case1可以考虑，case2,3不建议业务中使用通用方法。
            using (var scope = _serviceScopeFactory.CreateScope())
            {
                var dbContext = scope.ServiceProvider.GetRequiredService<JobManagerDbContext>();
                // 在此处使用dbContext进行数据库操作
                await dbContext.SysLogOperation.AddAsync(operationLog);
                await dbContext.SaveChangesAsync();
            }

        }


        private string GetBody(FilterContext context)
        {
            // 获取请求Body内容
            string requestBody = string.Empty;
            #region 请求
            if (Convert.ToBoolean((context.HttpContext.Request?.ContentType?.Contains("application/json"))))
            {
                context.HttpContext.Request.EnableBuffering();
                var requestReader = new StreamReader(context.HttpContext.Request.Body);
                requestBody = requestReader.ReadToEnd();
                context.HttpContext.Request.Body.Position = 0;
            }
            return requestBody;
            #endregion
        }
    }

    /// <summary>
    /// 操作日志标记
    /// </summary>
    public class OperationLogTag : Attribute
    {
        private readonly bool IsWrite;//是否需要记录日志
        private readonly string Title;//自定义日志标题
        private readonly RecordBody RecordBody;//记录请求体的长度


        public OperationLogTag(bool isWrite = true, string title = null, RecordBody recordBody = RecordBody.part)
        {
            this.IsWrite = isWrite;
            this.Title = title;
            this.RecordBody = recordBody;
        }
    }

    public enum RecordBody
    {
        none,
        part,
        all
    }
}
